package br.edu.ufcg.lsd.wbis.ui.server;

import static br.edu.ufcg.lsd.wbis.ui.server.ControllerAccesser.getController;
import static br.edu.ufcg.lsd.wbis.ui.server.Util.getEquivalentLevel;
import static br.edu.ufcg.lsd.wbis.ui.server.Util.getMatcher;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import br.edu.ufcg.lsd.wbis.control.equipment.Equipment;
import br.edu.ufcg.lsd.wbis.control.user.User;
import br.edu.ufcg.lsd.wbis.control.user.UserMatcher;
import br.edu.ufcg.lsd.wbis.ui.client.beans.EquipInfo;
import br.edu.ufcg.lsd.wbis.ui.client.beans.UserInfo;
import br.edu.ufcg.lsd.wbis.ui.client.beans.UserInfo.UserPermission;
import br.edu.ufcg.lsd.wbis.ui.client.services.UserService;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class UserServiceImpl extends RemoteServiceServlet implements UserService {

	private static final long serialVersionUID = 1L;

	/**
	 * {@inheritDoc}
	 */
	public UserInfo updatePersonalInfo(String login, String password, UserInfo newInfo) {
		try {
			getController().updateUserInfo(login, password, newInfo.getLogin(), newInfo.getName(), newInfo.getEmail(),
					getEquivalentLevel(newInfo.getLevel()), newInfo.isAuthorized());
			User user = getController().getUser(login, password, newInfo.getLogin());
			UserInfo brandNewInfo = new UserInfo();
			brandNewInfo.setLogin(user.getLogin());
			brandNewInfo.setPassword(newInfo.getPassword());
			brandNewInfo.setName(user.getName());
			brandNewInfo.setEmail(user.getEmail());
			brandNewInfo.setLevel(getEquivalentLevel(user.getLevel()));
			brandNewInfo.setAuthorized(user.isAuthorized());
			return brandNewInfo;
		} catch (Throwable e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public UserInfo changePassword(String login, String password, UserInfo newInfo) {
		try {
			getController().updateUserPassword(login, password, newInfo.getLogin(), newInfo.getPassword());
			User user = getController().getUser(login, password, newInfo.getLogin());
			UserInfo brandNewInfo = new UserInfo();
			brandNewInfo.setLogin(user.getLogin());
			brandNewInfo.setPassword(newInfo.getPassword());
			brandNewInfo.setName(user.getName());
			brandNewInfo.setEmail(user.getEmail());
			brandNewInfo.setLevel(getEquivalentLevel(user.getLevel()));
			brandNewInfo.setAuthorized(user.isAuthorized());
			return brandNewInfo;
		} catch (Throwable e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public UserInfo getUserInfo(String login, String password, String userLogin) {
		try {
			User user = getController().getUser(login, password, userLogin);
			UserInfo info = new UserInfo();
			info.setLogin(userLogin);
			info.setName(user.getName());
			info.setEmail(user.getEmail());
			info.setLevel(getEquivalentLevel(user.getLevel()));
			info.setAuthorized(user.isAuthorized());
			return info;
		} catch (Throwable e) {
			e.printStackTrace();
			throw new RuntimeException(e.getCause());
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public List<UserInfo> getRandomUserInfos(String login, String password, int n) {
		try {
			List<User> users = getController().getUsers(login, password);
			List<UserInfo> result = new ArrayList<UserInfo>(n);
			for (int i = 0; i < n; i++) {
				User randomUser = users.get((int) (Math.random() * users.size()));
				UserInfo info = new UserInfo();
				info.setLogin(randomUser.getLogin());
				info.setName(randomUser.getName());
				info.setEmail(randomUser.getEmail());
				info.setLevel(getEquivalentLevel(randomUser.getLevel()));
				info.setAuthorized(randomUser.isAuthorized());
				result.add(info);
			}
			return result;
		} catch (Throwable e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public List<UserInfo> getRandomUnauthorizedUserInfos(UserInfo requester) {
		try {
			List<User> users = getController().searchUsers(requester.getLogin(), requester.getPassword(), new UserMatcher().setAuthorized(false));
			List<UserInfo> result = new ArrayList<UserInfo>(users.size());
			for (User user : users) {
				UserInfo info = new UserInfo();
				info.setLogin(user.getLogin());
				info.setName(user.getName());
				info.setEmail(user.getEmail());
				info.setLevel(getEquivalentLevel(user.getLevel()));
				info.setAuthorized(user.isAuthorized());
				result.add(info);
			}
			if (result.isEmpty()) {
				UserInfo noUser = new UserInfo();
				noUser.setLogin("login");
				noUser.setName("name");
				noUser.setEmail("email");
				noUser.setLevel(UserPermission.COMMON_USER);
				noUser.setAuthorized(false);
				result.add(noUser);
			}
			return result;
		} catch (Throwable e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public void authorizeUser(String login, String password, String loginToAuthorize) {
		try {
			User user = getController().getUser(login, password, loginToAuthorize);
			getController().authorizeUser(login, password, user.getLogin(), true);
		} catch (Throwable e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public List<String> getUsersNames(String login, String password) {
		try {
			List<User> users = getController().getUsers(login, password);
			List<String> usersNames = new ArrayList<String>(users.size());
			for (User user : users) {
				usersNames.add(user.getLogin());
			}
			Collections.sort(usersNames);
			return usersNames;
		} catch (Throwable e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	/**
	 * @return
	 */
	public List<UserInfo> getAllUserInfos(String login, String password) {
		try {
			List<User> users = getController().getUsers(login, password);
			List<UserInfo> result = new ArrayList<UserInfo>();
			for (User user : users) {
				UserInfo info = new UserInfo();
				info.setLogin(user.getLogin());
				info.setName(user.getName());
				info.setEmail(user.getEmail());
				info.setLevel(getEquivalentLevel(user.getLevel()));
				info.setAuthorized(user.isAuthorized());
				result.add(info);
			}
			return result;
		} catch (Throwable e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public List<UserInfo> searchUsers(UserInfo requester, br.edu.ufcg.lsd.wbis.ui.client.beans.UserMatcher matcher) {
		try {
			List<User> users = getController().searchUsers(requester.getLogin(), requester.getPassword(), getMatcher(matcher));
			List<UserInfo> result = new ArrayList<UserInfo>(users.size());
			for (User user : users) {
				UserInfo info = new UserInfo();
				info.setLogin(user.getLogin());
				info.setName(user.getName());
				info.setEmail(user.getEmail());
				info.setLevel(getEquivalentLevel(user.getLevel()));
				info.setAuthorized(user.isAuthorized());
				result.add(info);
			}
			return result;
		} catch (Throwable e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	public UserInfo registerUser(String login, String password, UserInfo userInfo) {
		try {
			User user = getController().addUser(login, password, userInfo.getLogin(), userInfo.getPassword(), userInfo.getName(), userInfo.getEmail(), getEquivalentLevel(userInfo.getLevel()), userInfo.isAuthorized());
			UserInfo returnInfo = new UserInfo();
			returnInfo.setName(user.getName());
			returnInfo.setEmail(user.getEmail());
			returnInfo.setLogin(user.getLogin());
			returnInfo.setLevel(getEquivalentLevel(user.getLevel()));
			returnInfo.setAuthorized(user.isAuthorized());
			return returnInfo;
		} catch (Throwable e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}
	
	public void removeUser(String login, String password, String loginToRemove) {
		try {
			getController().removeUser(login, password, loginToRemove);
		} catch (Throwable e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}
	
	// FIXME: move the method below to its own service

	/**
	 * {@inheritDoc}
	 */
	public List<EquipInfo> getAllEquipmentInfos(String requesterLogin, String requesterPassword) {
		try {
			List<Equipment> equips = getController().getAllEquipments(requesterLogin, requesterPassword);
			List<EquipInfo> result = new ArrayList<EquipInfo>();
			for (Equipment equip : equips) {
				EquipInfo info = new EquipInfo();
				info.setInventoryCode(equip.getInventoryCode());
				info.setType(equip.getType());
				info.setModel(equip.getModel());
				info.setBrand(equip.getBrand());
				info.setLocalization(equip.getLocalization());
				info.setAcqDate(equip.getAcquisitionDate());
				info.setAllocable(equip.isAlocable());
				info.setAvailable(equip.isAvailable());
				info.setSerialCode(equip.getSerialCode());
				result.add(info);
			}
			return result;
		} catch (Throwable e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

}
